package com.hzhc.service.impl;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.TemplateExportParams;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hzhc.Thread.SendMessageThread;
import com.hzhc.common.FileExcelUtil;
import com.hzhc.entity.TrainPlan;
import com.hzhc.entity.TrainPlanDetail;
import com.hzhc.entity.UserMember;
import com.hzhc.enumBean.MsgPushEnum;
import com.hzhc.enumBean.ResultUtilCodeEnum;
import com.hzhc.enumBean.SendMsgType;
import com.hzhc.mapper.TrainPlanDetailMapper;
import com.hzhc.mapper.TrainPlanMapper;
import com.hzhc.mapper.UserMemberMapper;
import com.hzhc.mapper.YwOrderCntrMapper;
import com.hzhc.service.*;
import com.hzhc.utils.ResultUtil;
import com.hzhc.utils.StringUtils;
import com.hzhc.vo.*;
import lombok.RequiredArgsConstructor;
import org.apache.poi.ss.formula.functions.T;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 班列计划 服务实现类
 * </p>
 *
 * @author 1
 * @since 2024-05-29
 */
@Service
@RequiredArgsConstructor
public class TrainPlanServiceImpl extends ServiceImpl<TrainPlanMapper, TrainPlan> implements TrainPlanService {

    private final TrainPlanDetailMapper detailMapper;

    private final CntrInfoService infoService;

    private final YwOrderCntrMapper orderCntrMapper;

    private final SmsTemplateService smsTemplateService;

    private final ThreadPoolTaskExecutor taskExecutor;

    private final UserMemberMapper userMemberMapper;

    private final PushService pushService;

    private final SysMsgNotifyService notifyService;

    private final CompanyInfoService companyInfoService;

    @Override
    public List<TrainPlanVo> getTrainPlanList(Page<TrainPlanVo> page, TrainPlanVo vo) {
        IPage<TrainPlanVo> iPage = baseMapper.getTrainPlanList(page,vo);
        List<TrainPlanVo> voList = iPage.getRecords();
        for (TrainPlanVo planVo : voList) {
            planVo.setTeu(planVo.getTeu()+planVo.getTeu2()*2);
        }

        return voList;
    }

    @Override
    public ResultUtil<T> addTrainPlan(TrainPlan plan) {
        if (save(plan)){
            return ResultUtil.ok();
        }
        return ResultUtil.fail();
    }

    @Override
    public ResultUtil<T> updateTrainPlan(TrainPlan plan) {
        if (updateById(plan)){
            return ResultUtil.ok();
        }
        return ResultUtil.fail();
    }

    @Override
    public ResultUtil<T> deleteTrainPlan(Long id) {
        TrainPlan plan = getById(id);
        List<TrainPlanDetail> trainPlanDetails = detailMapper.selectList(new QueryWrapper<TrainPlanDetail>()
                .eq("disable", 0).eq("plan_id",plan.getId()).ne("tally_flag",0));
        if(trainPlanDetails.size()>0){
            return ResultUtil.build(ResultUtilCodeEnum.YWCNTR_IS_TALLY);
        }
        //plan表删除
        plan.setDisable(1);
        updateById(plan);
        //plan_detail表删除
        LambdaUpdateWrapper<TrainPlanDetail> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(TrainPlanDetail::getPlanId,id)
                .set(TrainPlanDetail::getDisable,1);
        detailMapper.update(null,wrapper);
        return ResultUtil.ok();
    }

    @Override
    public ResultUtil<T> updateChangeZl(Long id) {
        TrainPlan plan = getById(id);
        if ("XC".equals(plan.getType())){
            String planNo = plan.getTrainPlanNo();
            String planNoNew = planNo.replace("X", "F");
            TrainPlan plan1 = new TrainPlan();
            plan1.setTrainPlanNo(planNoNew);
            plan1.setPlanWorkTime(LocalDateTime.now());
            plan1.setType("ZC");
            plan1.setUserId(plan.getUserId());
            plan1.setCreateTime(LocalDateTime.now());
            plan1.setStrands(plan.getStrands());
//            baseMapper.insert(plan1);
        }

        plan.setLoadZl(1);
        if (updateById(plan)){
            return ResultUtil.ok();
        }
        return ResultUtil.fail();
    }

    @Override
    public List<TrainPlanVo> getAppTrainPlanList(Page<TrainPlanVo> page, TrainPlanVo vo) {
        IPage<TrainPlanVo> iPage = baseMapper.getTrainPlanList(page,vo);
        return iPage.getRecords();
    }

    @Override
    public List<TrainPlanVo> selectInOutPortMonthList(TrainPlanVo vo) {

        List<TrainPlanVo> resultList = new ArrayList<>();
        //获取月份第一天和最后一天时间
        LocalDate now = vo.getPlanTime();
//        now = now.minusMonths(0);//月份-1
        // 获取当前月的第一天
        LocalDateTime firstDay = now.with(TemporalAdjusters.firstDayOfMonth()).atTime(0,0,0);
        // 获取当前月的最后一天
        LocalDateTime lastDay = now.with(TemporalAdjusters.lastDayOfMonth()).atTime(23,59,59);
        vo.setStartTime(firstDay);
        vo.setEndTime(lastDay);
        List<TrainPlanVo> list = baseMapper.getCalendar(vo);

        int hjzrx = 0;
        int hjTeu = 0;
        for (TrainPlanVo trainPlanVo : list) {
            int ckteu = 0;
            List<TrainPlanDetailVo> cntrVoList= detailMapper.getListGroupByCntrSize(trainPlanVo);
            TrainPlanVo vo1 = new TrainPlanVo();
            vo1.setCk20(0);
            vo1.setCk40(0);
            vo1.setCk45(0);
            vo1.setTrainPlanName(trainPlanVo.getTrainPlanName());
            vo1.setCreateTime(trainPlanVo.getCreateTime());
            for (TrainPlanDetailVo detailVo : cntrVoList) {
                if(detailVo.getCntrSize().startsWith("20")){
                    vo1.setCk20(detailVo.getNum());
                    ckteu += detailVo.getNum();
                }else if(detailVo.getCntrSize().startsWith("40")){
                    vo1.setCk40(detailVo.getNum());
                    ckteu += detailVo.getNum()*2;
                }else{
                    vo1.setCk45(detailVo.getNum());
                    ckteu += detailVo.getNum()*2;
                }
            }
            vo1.setTeu(ckteu);//单个班列 小计
            hjzrx+=vo1.getCk20()+vo1.getCk40()+vo1.getCk45();
            hjTeu+=vo1.getTeu();
            if (!(vo1.getCk20()==0 && vo1.getCk40()==0 && vo1.getCk45()==0)){
                resultList.add(vo1);
            }
        }
        for (TrainPlanVo planVo : resultList) {
            planVo.setHjzrx(hjzrx);
            planVo.setHjTeu(hjTeu);
        }
        resultList.sort(Comparator.comparing(TrainPlanVo::getCreateTime));//按时间排序
        return resultList;
    }

    @Override
    public List<CalendarVo> getCalendar(TrainPlanVo vo) {
        List<TrainPlanVo> list=baseMapper.getCalendar(vo);
        Map<LocalDate, List<TrainPlanVo>> collect = list.stream().collect(Collectors.groupingBy(TrainPlanVo::getGroupTime));

        Iterator<Map.Entry<LocalDate, List<TrainPlanVo>>> iterator = collect.entrySet().iterator();
        List<CalendarVo> list1=new ArrayList();
        while (iterator.hasNext()) {
            Map.Entry<LocalDate, List<TrainPlanVo>> entry = iterator.next();
            CalendarVo calendarVo=new CalendarVo();
            calendarVo.setDay(entry.getKey().toString());
            List<String> stringList=new ArrayList<>();
            for (TrainPlanVo trainPlanVo : entry.getValue()) {
                stringList.add(trainPlanVo.getTrainPlanNo());
//                stringList.add(trainPlanVo.getBeginStation()+"-"+trainPlanVo.getEndStation());
                calendarVo.setTrainPlanId(trainPlanVo.getId());
                calendarVo.setType(trainPlanVo.getType());
                calendarVo.setTrainPlanNo(trainPlanVo.getTrainPlanNo());
            }
            calendarVo.setStrList(stringList);
            list1.add(calendarVo);
        }
        return list1;
    }

    private final static String MONTH_REPORT_EXCEL_PATH = "static/download/班吞吐量列统计表.xlsx";

    @Override
    public void exportMonthReport(TrainPlanVo vo, HttpServletRequest request, HttpServletResponse response) {
        Map<String, Object> map = selectInOutPortMonthList1(vo);
        map.put("planTime",vo.getPlanTime().format(DateTimeFormatter.ofPattern("yyyy/MM")));
        TemplateExportParams params = new TemplateExportParams(MONTH_REPORT_EXCEL_PATH);
        Workbook book = ExcelExportUtil.exportExcel(params, map);
        FileExcelUtil.downloadExcelIo(book, request, response, "班吞吐量列统计表");
    }

    @Override
    public JSONObject getIndexTop() {
        JSONObject jsonObject = new JSONObject();
        Integer cntrFyTotal = 0;
        Integer cntrDdTotal = 0;
        List<TrainPlanVo> list = baseMapper.getTrainPlanCount();
        List<TrainPlanVo> planFy = baseMapper.getTrainPlanFyCount();
        List<TrainPlanVo> planDd = baseMapper.getTrainPlanDdCount();
        for (TrainPlanVo planCVo : planFy) {
            cntrFyTotal+=planCVo.getCntrFyTotal();
        }
        for (TrainPlanVo planCVo : planDd) {
            cntrDdTotal+=planCVo.getCntrDdTotal();
        }
        jsonObject.put("num",list.size());// 发运班列数
        jsonObject.put("cntrFyTotal",cntrFyTotal);//发运箱数
        jsonObject.put("cntrDdTotal",cntrDdTotal);//到达箱数
        return jsonObject;
    }

    @Override
    public JSONObject getIndexCenter() {
        JSONObject jsonObject = new JSONObject();
        // 当日班列
        List<TrainPlanVo> todayPlan = baseMapper.getTodayPlan();
        for (TrainPlanVo trainPlanVo : todayPlan) {
            List<TrainPlanDetail> trainPlanCntrs = detailMapper.selectList(new QueryWrapper<TrainPlanDetail>()
                    .eq("disable", 0)
                    .eq("plan_id", trainPlanVo.getId()));
            if (!trainPlanCntrs.isEmpty()){
                List<TrainPlanDetail> collect = trainPlanCntrs.stream().filter(s -> s.getTallyFlag() == 1).collect(Collectors.toList());
                trainPlanVo.setCntrLhTotal(collect.size());//已理货箱数
                trainPlanVo.setCntrNum(trainPlanCntrs.size());//总箱数
            }else {
                trainPlanVo.setCntrNum(0);
                trainPlanVo.setCntrLhTotal(0);
            }

        }
        jsonObject.put("todayPlan",todayPlan);
        return jsonObject;
    }

    @Override
    public JSONObject getIndexBottomPie() {
        JSONObject jsonObject = new JSONObject();
        // 统计图
        List<JSONObject> zcEf = infoService.getZcEfCountCensus();//空、重箱
        List<JSONObject> zcSize = infoService.getZcSizeCensus();//大、小箱
        jsonObject.put("zcEf",zcEf);
        jsonObject.put("zcSize",zcSize);
        return jsonObject;
    }

    @Override
    public JSONObject getIndexCompanyRank() {
        JSONObject jsonObject = new JSONObject();
        // 货代排行按箱量
        List<YwOrderCntrVo> cntrVos = orderCntrMapper.getHdRankingByCntr();
        jsonObject.put("hdCntr",cntrVos);
        return jsonObject;
    }

    @Override
    public JSONArray getIndexColumn() {
        JSONObject obj = new JSONObject();
        JSONArray array = new JSONArray();
        List<TrainPlanVo> list = baseMapper.getTrainPlanCount();
        long fyCount = list.stream().filter(u -> "ZC".equals(u.getType())).count();
        long xcCount = list.stream().filter(u -> "XC".equals(u.getType())).count();

        obj.put("value",fyCount);//发运装车个数
        obj.put("name","发运车");//发运装车个数
        array.add(obj);
        JSONObject obj1 = new JSONObject();

        obj1.put("value",xcCount);//到达卸车个数
        obj1.put("name","到达车");//到达卸车个数
        array.add(obj1);
        return array;
    }

    @Override
    public ResultUtil<T> updateTrainPlanArea(TrainPlanVo vo) {
        TrainPlan plan = getById(vo.getId());
        plan.setArea(vo.getArea());
        plan.setUpdateTime(LocalDateTime.now());
        plan.setUpdateUserId(vo.getUpdateUserId());
        boolean b = updateById(plan);
        if (b){
            return ResultUtil.ok();
        }
        return ResultUtil.fail();
    }

    @Override
    public ResultUtil<T> updateSendNotice(TrainPlanVo vo) {
        List<Long> companyNames = vo.getSelCompanyList().stream().map(CompanyInfoVo::getId).collect(Collectors.toList());
        List<UserMember> userMembers = userMemberMapper.selectList(new LambdaUpdateWrapper<UserMember>().in(UserMember::getCompanyId, companyNames));
        //给公司的联系人发送通知提醒
//        for (CompanyInfoVo companyInfoVo : vo.getSelCompanyList()){
//            TrainPlanVo trainPlanVo= new TrainPlanVo();
//            trainPlanVo.setTelephone(companyInfoVo.getTelephone());
//            trainPlanVo.setBeginStation(vo.getBeginStation());
//            //发送短信
//            SendMessageThread sendMessageThread = new SendMessageThread(trainPlanVo,smsTemplateService);
//            taskExecutor.execute(sendMessageThread);
//        }

        //给公司下的每个账户发送通知提醒
        for (UserMember userMember:userMembers){
            //发送短信通知
            TrainPlanVo trainPlanVo= new TrainPlanVo();
            trainPlanVo.setTelephone(userMember.getTelephone());
            trainPlanVo.setBeginStation(vo.getBeginStation());
            //发送短信
            SendMessageThread sendMessageThread = new SendMessageThread(trainPlanVo,smsTemplateService);
            taskExecutor.execute(sendMessageThread);
            //发送websocket通知
            String content = "贵公司从"+vo.getBeginStation()+"发出的集装箱已到达阳逻铁水联运示范基地一期，请尽快至网上服务厅办理提箱手续，以免超期产生不必要的额外费用，感谢您的配合!";
            String type = MsgPushEnum.yzstx.getName();
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("content",content);
            jsonObject.put("type",type);
            pushService.pushMsgToOne(String.valueOf(userMember.getId()),jsonObject.toJSONString());
        }
        return ResultUtil.ok();
    }


    private Map<String, Object> selectInOutPortMonthList1(TrainPlanVo vo) {
        //获取月份第一天和最后一天时间
        LocalDate now = vo.getPlanTime();
//        now = now.minusMonths(0);//月份-1
        // 获取当前月的第一天
        LocalDateTime firstDay = now.with(TemporalAdjusters.firstDayOfMonth()).atTime(0,0,0);
        // 获取当前月的最后一天
        LocalDateTime lastDay = now.with(TemporalAdjusters.lastDayOfMonth()).atTime(23,59,59);
        vo.setStartTime(firstDay);
        vo.setEndTime(lastDay);
        List<TrainPlanVo> list = baseMapper.getCalendar(vo);
        Map<String, JSONObject> mapCk = new HashMap<>();
        int hjzrx = 0;
        int hjTeu = 0;
        for (TrainPlanVo trainPlanVo : list) {
            int ckteu = 0;
            List<TrainPlanDetailVo> cntrVoList= detailMapper.getListGroupByCntrSize(trainPlanVo);

            JSONObject obj = new JSONObject();
            obj.put("trainPlanNo","");
            obj.put("ck20",0);
            obj.put("ck40",0);
            obj.put("ck45",0);
            for (TrainPlanDetailVo trainPlanCntrVo : cntrVoList) {
                obj.put("trainPlanNo",trainPlanVo.getTrainPlanName());
                if(trainPlanCntrVo.getCntrSize().startsWith("20")){
                    obj.put("ck20",trainPlanCntrVo.getNum());
                    ckteu += trainPlanCntrVo.getNum();
                }else if(trainPlanCntrVo.getCntrSize().startsWith("40")){
                    obj.put("ck40",trainPlanCntrVo.getNum());
                    ckteu += trainPlanCntrVo.getNum()*2;
                }else{
                    obj.put("ck45",trainPlanCntrVo.getNum());
                    ckteu += trainPlanCntrVo.getNum()*2;
                }
            }
            obj.put("ckteu",ckteu);
            if(!cntrVoList.isEmpty()){
                mapCk.put(trainPlanVo.getTrainPlanName(), obj);
            }

            hjzrx+=obj.getInteger("ck20")+obj.getInteger("ck40")+obj.getInteger("ck45");
            hjTeu+=obj.getInteger("ckteu");
        }

        //返回结果集map 按照班列日期从早到晚排序
        LinkedHashMap<String, JSONObject> map = mapCk.entrySet()
                .stream()
                .sorted(Map.Entry.comparingByKey())
                .collect(Collectors.toMap(Map.Entry::getKey,
                        Map.Entry::getValue,
                        (oldVal, newVal) -> oldVal,
                        LinkedHashMap::new));
        List<JSONObject> ckList = new ArrayList<>(map.values());//map

        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("list", ckList);
        resultMap.put("hjzrx", hjzrx);
        resultMap.put("hjTeu", hjTeu);
        return resultMap;

    }

    @Override
    public ResultUtil<T> wgTrainPlan(TrainPlanVo vo) {
        TrainPlan plan = getById(vo.getId());
        plan.setUpdateUserId(vo.getUpdateUserId());
        if ("ZC".equals(plan.getType())){//装车
            List<TrainPlanDetail> trainPlanDetails = detailMapper.selectList(new QueryWrapper<TrainPlanDetail>().eq("disable", 0)
                    .eq("plan_id", plan.getId()));
            List<TrainPlanDetail> unTallyList = trainPlanDetails.stream().filter(s -> s.getTallyFlag() == 0).collect(Collectors.toList());
            List<TrainPlanDetail> unFinishList = trainPlanDetails.stream().filter(s -> StringUtils.isEmpty(s.getWgTrip())).collect(Collectors.toList());
            if (unTallyList.size()>0){
                return ResultUtil.build(400,"该班列下还有未理货的箱子！");
            }
            if (unFinishList.size()>0){
                return ResultUtil.build(400,"该班列下还有未车次完工的箱子！");
            }
        }
        plan.setFinishTime(LocalDateTime.now());
        plan.setUpdateTime(LocalDateTime.now());
        plan.setStatus(10);
        boolean b = updateById(plan);
        if (b && "XC".equals(plan.getType())){
            //卸车发送消息提醒
            List<String> comIds = detailMapper.getCompanyIdList(plan.getId());//卸车计划箱清单  关联的公司id
            List<UserMemberVo> userIds = new ArrayList<>();//公司下的人
            if (comIds!=null && comIds.size()>0){
                userIds = userMemberMapper.getSendMsgUserIds(comIds,plan.getId());
            }else {
                userIds = null;
            }
            //卸车完工save
            notifyService.saveMsg(plan,userIds);
        }
        return b?ResultUtil.ok(): ResultUtil.fail();
    }

    @Override
    public List<TrainPlan> getXcPlanList() {
        return baseMapper.getXcPlanList();
    }

    @Override
    public List<TrainPlanVo> getAppXcTrainPlanList(Page<TrainPlanVo> page, TrainPlanVo vo) {
        IPage<TrainPlanVo> iPage = baseMapper.getAppXcTrainPlanList(page,vo);
        return iPage.getRecords();
    }

    @Override
    public List<TrainPlanVo> getWxTrainPlanList(Page<TrainPlanVo> page, TrainPlanVo vo) {
        IPage<TrainPlanVo> iPage = baseMapper.getWxTrainPlanList(page,vo);
        return iPage.getRecords();
    }

    @Override
    public ResultUtil<T> updateFinishStatus(TrainPlanVo vo) {
        TrainPlan plan = getById(vo.getId());
        if ("ZC".equals(plan.getType())){//装车
            List<TrainPlanDetail> trainPlanDetails = detailMapper.selectList(new QueryWrapper<TrainPlanDetail>().eq("disable", 0)
                    .eq("plan_id", plan.getId()));
            List<TrainPlanDetail> unTallyList = trainPlanDetails.stream().filter(s -> s.getTallyFlag() == 0).collect(Collectors.toList());
            List<TrainPlanDetail> unFinishList = trainPlanDetails.stream().filter(s -> StringUtils.isEmpty(s.getWgTrip())).collect(Collectors.toList());
            if (unTallyList.size()>0){
                return ResultUtil.build(400,"该班列下还有未理货的箱子！");
            }
            if (unFinishList.size()>0){
                return ResultUtil.build(400,"该班列下还有未车次完工的箱子！");
            }
        }
        plan.setStatus(10);
        plan.setFinishTime(LocalDateTime.now());//当前时间
        plan.setUpdateUserId(vo.getUpdateUserId());
        boolean b = updateById(plan);
        if (b && "XC".equals(plan.getType())){
            //卸车发送消息提醒
            List<String> comIds = detailMapper.getCompanyIdList(plan.getId());//卸车计划箱清单  关联的公司id
            List<UserMemberVo> userIds = new ArrayList<>();//公司下的人
            if (comIds!=null && comIds.size()>0){
                userIds = userMemberMapper.getSendMsgUserIds(comIds,plan.getId());
            }else {
                userIds = null;
            }
            //卸车完工save
            notifyService.saveMsg(plan,userIds);
        }
        if (b){
            return ResultUtil.ok();
        }
        return ResultUtil.fail();
    }


}
